/**
 *****************************************************************************
 * @file
 * @brief
 * @author Moon
 * @version V1.0.0
 * @date 2021/05/19
 ****************************************************************************
 */

/* Includes ---------------------------------------------------------------*/
#include <string.h>
#include "drv_f4_delay_168MHz.h"

#include "public_crc16_rtu.h"
#include "ParmManage.h"

/* Private defines ---------------------------------------------------------------*/
#define SYSTEM_ID_BASE			(0)
#define APP_ID_BASE				(PP_SYSTEM_ID_MAX)
#define UPDATE_ID_BASE			(PP_APP_ID_MAX)
#define PP_ID_MAX_NUM			(PP_UPDATE_ID_MAX)

#if defined(USE_INTERNAL_FLASH) || defined(USE_EXTERNAL_FLASH)
	#define PARM_MAP_SIZE   		(SYSTEM_REGION_SIZE + APP_REGION_SIZE + UPDATE_REGION_SIZE)

	#define SYSTEM_MAP_BASE			(parm_map)
	#define APP_MAP_BASE			(SYSTEM_MAP_BASE + SYSTEM_REGION_SIZE)
	#define UPDATE_MAP_BASE			(APP_MAP_BASE + APP_REGION_SIZE)

#elif defined(USE_EXTERNAL_FRAM)	// FRAM模式下，系统和应用参数没有缓存表
	#define PARM_MAP_SIZE   		(UPDATE_REGION_SIZE)

	#define UPDATE_MAP_BASE			(parm_map)

	#define FRAM_SYSTEM_FLAG_ADDR	(parm_info_map[PP_SYSTEM_CRC].offset)
	#define FRAM_APP_FLAG_ADDR		(parm_info_map[PP_APP_CRC].offset)

	#define IAP_FRAM_READ(addr, data, len)		att_fram->Read(att_fram, addr, data, len)
	#define IAP_FRAM_WRITE(addr, data, len)		att_fram->Write(att_fram, addr, data, len)

#endif

/* Private Struct ---------------------------------------------------------------*/

/* Private enum ---------------------------------------------------------------*/

/* Private Variable ---------------------------------------------------------------*/
drv_flash_t	*att_flash;
#if defined USE_EXTERNAL_FRAM	// FRAM模式下，系统和应用参数没有缓存表
dev_fm24_t *att_fram;
#endif
//Pointer

//Array
#include "parm_map.h"

#if SYSTEM_REGION_SIZE > STORAGE_PARM_SYSTEM_SIZE
    #error System parameter space is exceeded.
#endif

#if APP_REGION_SIZE > STORAGE_PARM_APP_SIZE
    #error APP parameter space is exceeded.
#endif

#if UPDATE_REGION_SIZE > STORAGE_PARM_UPATAE_SIZE
    #error Upadte parameter space is exceeded.
#endif

//Const
static uint8_t parm_map[PARM_MAP_SIZE];
static uint8_t parm_system_init_flag, parm_app_init_flag, parm_update_init_flag;

#if defined(USE_EXTERNAL_FRAM)
	static uint8_t FRAM_defalut_app_init_state, FRAM_app_init_state, \
		FRAM_default_system_init_state, FRAM_system_init_state, FRAM_store_mode = FRAM_NORMAL_MODE;
#endif

/* Private function prototypes -----------------------------------------------*/

/*****************************************************************************
 * @brief 应用程序读取接口函数
 * ex:
 * @par
 * None
 * @retval
 *****************************************************************************/
uint8_t PPItemRead(uint16_t id, uint8_t *data, uint16_t len)
{
	// 检查传入参数正确性
	if (id >= PP_ID_MAX_NUM || !data || len > parm_info_map[id].size) {
		return 1;
	}

#if defined(USE_INTERNAL_FLASH) || defined(USE_EXTERNAL_FLASH)
	uint8_t *buf_addr;

	if (id >= UPDATE_ID_BASE) {
		buf_addr = UPDATE_MAP_BASE;
	} else if (id >= APP_ID_BASE) {
		buf_addr = APP_MAP_BASE;
	} else {
		buf_addr = SYSTEM_MAP_BASE;
	}

	buf_addr += parm_info_map[id].offset;
	memcpy(data, buf_addr, len);

#elif defined(USE_EXTERNAL_FRAM)

	if (id >= UPDATE_ID_BASE) {
		// 升级区数据
		memcpy(data, UPDATE_MAP_BASE + parm_info_map[id].offset, len);
	} else {
		uint32_t addr;

		if (id >= APP_ID_BASE) {
			// 应用区数据
			if (FRAM_store_mode == FRAM_DEFAULT_MODE) {
				addr = STORAGE_PARM_DEFAULT_APP_BASE;
			} else {
				addr = STORAGE_PARM_APP_BASE;
			}
		} else {
			// 系统区数据
			if (FRAM_store_mode == FRAM_DEFAULT_MODE) {
				addr = STORAGE_PARM_DEFAULT_SYSTEM_BASE;
			} else {
				addr = STORAGE_PARM_SYSTEM_BASE;
			}
		}
        
        taskENTER_CRITICAL();
		addr += parm_info_map[id].offset;
		IAP_FRAM_READ(addr, data, len);
        taskEXIT_CRITICAL();
	}
	
#endif

	return 0;
}

/*****************************************************************************
 * @brief 应用程序写入接口函数
 * ex:
 * @par
 * None
 * @retval
 *****************************************************************************/
uint8_t PPItemIWrite(uint16_t id, uint8_t *data, uint16_t len)
{
	// 检查传入参数正确性，长度不做限定
	if (id >= PP_ID_MAX_NUM || !data || len > parm_info_map[id].size) {
		return 1;
	}

#if defined(USE_INTERNAL_FLASH) || defined(USE_EXTERNAL_FLASH)

	uint8_t *buf_addr;

	if (id >= UPDATE_ID_BASE) {
		buf_addr = UPDATE_MAP_BASE;
	} else if (id >= APP_ID_BASE) {
		buf_addr = APP_MAP_BASE;
	} else {
		buf_addr = SYSTEM_MAP_BASE;
	}

	buf_addr += parm_info_map[id].offset;
	memcpy(buf_addr, data, len);

#elif defined(USE_EXTERNAL_FRAM)

	if (id >= UPDATE_ID_BASE) {
		// 升级区数据
		memcpy(UPDATE_MAP_BASE + parm_info_map[id].offset, data, len);
	} else {
		uint32_t addr;
		uint8_t read_back_buf[16];
		uint16_t read_back_len = 0;
		uint8_t read_len;

		if (id >= APP_ID_BASE) {
			// 应用区数据
			if (FRAM_store_mode == FRAM_DEFAULT_MODE) {
				addr = STORAGE_PARM_DEFAULT_APP_BASE;
			} else {
				addr = STORAGE_PARM_APP_BASE;
			}
		} else {
			// 系统区数据
			if (FRAM_store_mode == FRAM_DEFAULT_MODE) {
				addr = STORAGE_PARM_DEFAULT_SYSTEM_BASE;
			} else {
				addr = STORAGE_PARM_SYSTEM_BASE;
			}
		}

        taskENTER_CRITICAL();
		addr += parm_info_map[id].offset;
		IAP_FRAM_WRITE(addr, data, len);
        taskEXIT_CRITICAL();

		// 回读校验
		while (read_back_len < len) {
			read_len = (len - read_back_len > 16) ? 16 : len - read_back_len;
			IAP_FRAM_READ(addr + read_back_len, read_back_buf, read_len);
			if (memcmp(read_back_buf, data + read_back_len, read_len)) {
				return 1;
			}

			read_back_len += read_len;
		}
	}
	
#endif

	return 0;
}

/*****************************************************************************
 * @brief 应用程序保存系统和应用参数接口函数
 * ex:
 * @par
 * None
 * @retval
 *****************************************************************************/
uint8_t PPItemCopyToDataDevice(void)
{
	// RAM -> Flash
#if defined(USE_INTERNAL_FLASH) || defined(USE_EXTERNAL_FLASH)

	#if SYSTEM_REGION_SIZE > APP_REGION_SIZE
		uint8_t read_back_temp[SYSTEM_REGION_SIZE];
	#else
		uint8_t read_back_temp[APP_REGION_SIZE];
	#endif

	Crc16_Rtu_Create(SYSTEM_MAP_BASE, SYSTEM_REGION_SIZE, 0);
	att_flash->Erase(att_flash, STORAGE_PARM_SYSTEM_BASE, SYSTEM_REGION_SIZE);
	SoftDelayMs(100);
    att_flash->Write(att_flash, STORAGE_PARM_SYSTEM_BASE, SYSTEM_MAP_BASE, SYSTEM_REGION_SIZE);

	// 回读校验
	att_flash->Read(att_flash, STORAGE_PARM_SYSTEM_BASE, read_back_temp, SYSTEM_REGION_SIZE);
	if (memcmp(read_back_temp, SYSTEM_MAP_BASE, SYSTEM_REGION_SIZE)) {
		return 1;
	}

	Crc16_Rtu_Create(APP_MAP_BASE, APP_REGION_SIZE, 0);
	att_flash->Erase(att_flash, STORAGE_PARM_APP_BASE, APP_REGION_SIZE);
	SoftDelayMs(100);
    att_flash->Write(att_flash, STORAGE_PARM_APP_BASE, APP_MAP_BASE, APP_REGION_SIZE);

	// 回读校验
	att_flash->Read(att_flash, STORAGE_PARM_APP_BASE, read_back_temp, APP_REGION_SIZE);
	if (memcmp(read_back_temp, APP_MAP_BASE, APP_REGION_SIZE)) {
		return 1;
	}
	
#elif defined(USE_EXTERNAL_FRAM)

	// FRAM无需保存

#endif

	return 0;
}

/*****************************************************************************
 * @brief 应用程序保存升级参数接口函数
 * ex:
 * @par
 * None
 * @retval
 *****************************************************************************/
uint8_t PPUpdateInfoCopyToFlash(void)
{
	Crc16_Rtu_Create(UPDATE_MAP_BASE, UPDATE_REGION_SIZE, 0);
	att_flash->Erase(att_flash, STORAGE_PARM_UPATAE_BASE, UPDATE_REGION_SIZE);
	SoftDelayMs(100);
    att_flash->Write(att_flash, STORAGE_PARM_UPATAE_BASE, UPDATE_MAP_BASE, UPDATE_REGION_SIZE);

	// 回读校验
	uint8_t read_back_temp[UPDATE_REGION_SIZE];
	att_flash->Read(att_flash, STORAGE_PARM_UPATAE_BASE, read_back_temp, UPDATE_REGION_SIZE);
	if (memcmp(read_back_temp, UPDATE_MAP_BASE, UPDATE_REGION_SIZE)) {
		return 1;
	}
	
	return 0;
}

/*****************************************************************************
 * @brief 应用程序获取参数初始化状态接口函数
 * ex:
 * @par
 * None
 * @retval
 *****************************************************************************/
uint8_t PPGetInitFlag(uint16_t id)
{
	if (id >= PP_ID_MAX_NUM) {
		return 0;
	} else if (id >= UPDATE_ID_BASE) {
		return parm_update_init_flag;
	} else if (id >= APP_ID_BASE) {
		return parm_app_init_flag;
	} else {
		return parm_system_init_flag;
	}
}

/*****************************************************************************
 * @brief 参数初始化
 * ex:	drv_f:内部flash dev_f：外部铁电
 * @par
 * None
 * @retval
 *****************************************************************************/
int REG_PPInit(drv_flash_t *drv_f, dev_fm24_t *dev_f)
{
	att_flash = drv_f;
	Drv_Flash_Init(att_flash);

	// Flash -> RAM
#if defined(USE_INTERNAL_FLASH) || defined(USE_EXTERNAL_FLASH)

	// 读取系统参数
	att_flash->Read(att_flash, STORAGE_PARM_SYSTEM_BASE, SYSTEM_MAP_BASE, SYSTEM_REGION_SIZE);
	// 读取应用参数
	att_flash->Read(att_flash, STORAGE_PARM_APP_BASE, APP_MAP_BASE, APP_REGION_SIZE);
	
	// 系统参数CRC校验
	if (Crc16_Rtu_Verification(SYSTEM_MAP_BASE, SYSTEM_REGION_SIZE, 0)) {
		parm_system_init_flag = 1;
	} else {
		parm_system_init_flag = 0;
		memset(SYSTEM_MAP_BASE, 0, SYSTEM_REGION_SIZE);
	}
	// 应用参数CRC校验
	if (Crc16_Rtu_Verification(APP_MAP_BASE, APP_REGION_SIZE, 0)) {
		parm_app_init_flag = 1;
	} else {
		parm_app_init_flag = 0;
		memset(APP_MAP_BASE, 0, APP_REGION_SIZE);
	}

#elif defined(USE_EXTERNAL_FRAM)
	att_fram = dev_f;
	if (Dev_Fm24_Init(att_fram) != 0)
		return -1;
	// 读取FRAM存储区标志位
	//IAP_FRAM_READ(STORAGE_PARM_DEFAULT_SYSTEM_BASE + FRAM_SYSTEM_FLAG_ADDR, &FRAM_default_system_init_state, 1);
	IAP_FRAM_READ(STORAGE_PARM_SYSTEM_BASE + FRAM_SYSTEM_FLAG_ADDR, &FRAM_system_init_state, 1);
	//IAP_FRAM_READ(STORAGE_PARM_DEFAULT_APP_BASE + FRAM_APP_FLAG_ADDR, &FRAM_defalut_app_init_state, 1);
	IAP_FRAM_READ(STORAGE_PARM_APP_BASE + FRAM_APP_FLAG_ADDR, &FRAM_app_init_state, 1);
	FRAM_default_system_init_state = 0;
	FRAM_defalut_app_init_state = 0;
	// FRAM_system_init_state = 0;
    // FRAM_app_init_state = 0;
	// 不为0xAA，恢复默认
	if (FRAM_system_init_state != 0xAA) {
		if (FRAM_default_system_init_state == 0xAA) {
			// copy default -> normal
			uint8_t data[SYSTEM_REGION_SIZE - 4];
			IAP_FRAM_READ(STORAGE_PARM_DEFAULT_SYSTEM_BASE, data, SYSTEM_REGION_SIZE - 4);
			IAP_FRAM_WRITE(STORAGE_PARM_SYSTEM_BASE, data, SYSTEM_REGION_SIZE - 4);

			parm_system_init_flag = 1;
		} else {
			parm_system_init_flag = 0;
		}

		FRAM_system_init_state = 0xAA;
		IAP_FRAM_WRITE(STORAGE_PARM_SYSTEM_BASE + FRAM_SYSTEM_FLAG_ADDR, &FRAM_system_init_state, 1);
	} else {
		parm_system_init_flag = 1;
	}

	if (FRAM_app_init_state != 0xAA) {
		if (FRAM_defalut_app_init_state == 0xAA) {
			// copy default -> normal
			uint8_t data[APP_REGION_SIZE - 4];
			IAP_FRAM_READ(STORAGE_PARM_DEFAULT_APP_BASE, data, APP_REGION_SIZE - 4);
			IAP_FRAM_WRITE(STORAGE_PARM_APP_BASE, data, APP_REGION_SIZE - 4);

			parm_app_init_flag = 1;
		} else {
			parm_app_init_flag = 0;
		}
		
		FRAM_app_init_state = 0xAA;
		IAP_FRAM_WRITE(STORAGE_PARM_APP_BASE + FRAM_APP_FLAG_ADDR, &FRAM_app_init_state, 1);
	} else {
		parm_app_init_flag = 1;
	}

#endif

	// 读取升级参数
	att_flash->Read(att_flash, STORAGE_PARM_UPATAE_BASE, UPDATE_MAP_BASE, UPDATE_REGION_SIZE);
	// 升级参数CRC校验
	if (Crc16_Rtu_Verification(UPDATE_MAP_BASE, UPDATE_REGION_SIZE, 0)) {
		parm_update_init_flag = 1;
	} else {
		parm_update_init_flag = 0;
		memset(UPDATE_MAP_BASE, 0, UPDATE_REGION_SIZE);
	}
	return 0;
}

/*****************************************************************************
 * @brief 设置当前是默认还是动态区接口函数
 * ex:
 * @par
 * None
 * @retval
 *****************************************************************************/
void PPResetDefault(uint8_t mode)
{
#if defined(USE_INTERNAL_FLASH) || defined(USE_EXTERNAL_FLASH)
	if (mode == 2) {
		
		att_flash->Erase(att_flash, STORAGE_PARM_SYSTEM_BASE, SYSTEM_REGION_SIZE);
		SoftDelayMs(100);
		NVIC_SystemReset();
	} else if (mode == 3) {
		att_flash->Erase(att_flash, STORAGE_PARM_SYSTEM_BASE, SYSTEM_REGION_SIZE);
		SoftDelayMs(100);
		NVIC_SystemReset();
	}

#elif defined(USE_EXTERNAL_FRAM)
	if (mode == 2) 
    {
		if (FRAM_default_system_init_state == 0xAA) {
			uint8_t data[SYSTEM_REGION_SIZE - 4];
			IAP_FRAM_READ(STORAGE_PARM_DEFAULT_SYSTEM_BASE, data, SYSTEM_REGION_SIZE - 4);
			IAP_FRAM_WRITE(STORAGE_PARM_SYSTEM_BASE, data, SYSTEM_REGION_SIZE - 4);

			FRAM_system_init_state = 0xAA;
			IAP_FRAM_WRITE(STORAGE_PARM_SYSTEM_BASE + FRAM_SYSTEM_FLAG_ADDR, &FRAM_system_init_state, 1);
		} else {
			FRAM_system_init_state = 0x00;
			IAP_FRAM_WRITE(STORAGE_PARM_SYSTEM_BASE + FRAM_SYSTEM_FLAG_ADDR, &FRAM_system_init_state, 1);
		}

		NVIC_SystemReset();
	}

	if (mode == 3) {
		if (FRAM_defalut_app_init_state == 0xAA) {
			uint8_t data[APP_REGION_SIZE - 4];
			IAP_FRAM_READ(STORAGE_PARM_DEFAULT_APP_BASE, data, APP_REGION_SIZE - 4);
			IAP_FRAM_WRITE(STORAGE_PARM_APP_BASE, data, APP_REGION_SIZE - 4);

			FRAM_app_init_state = 0xAA;
			IAP_FRAM_WRITE(STORAGE_PARM_APP_BASE + FRAM_APP_FLAG_ADDR, &FRAM_app_init_state, 1);
		} else {
			FRAM_app_init_state = 0x00;
			IAP_FRAM_WRITE(STORAGE_PARM_APP_BASE + FRAM_APP_FLAG_ADDR, &FRAM_app_init_state, 1);
		}

		NVIC_SystemReset();
	}
	
#endif

	if (mode == 1) {
		att_flash->Erase(att_flash, STORAGE_PARM_APP_BASE, APP_REGION_SIZE);
		SoftDelayMs(100);
		NVIC_SystemReset();
	}
}

#if defined(USE_EXTERNAL_FRAM)
/*****************************************************************************
 * @brief 变更默认和动态区接口函数
 * ex:
 * @par
 * None
 * @retval
 *****************************************************************************/
void PPChangeStoreMode(uint8_t mode)
{
	if (mode == FRAM_DEFAULT_MODE) {
		FRAM_store_mode = FRAM_DEFAULT_MODE;

		// 切换至默认区时，若未初始化，用应用区初始化
		if (FRAM_default_system_init_state != 0xAA) {
			uint8_t data[SYSTEM_REGION_SIZE - 4];
			IAP_FRAM_READ(STORAGE_PARM_SYSTEM_BASE, data, SYSTEM_REGION_SIZE - 4);
			IAP_FRAM_WRITE(STORAGE_PARM_DEFAULT_SYSTEM_BASE, data, SYSTEM_REGION_SIZE - 4);
			
			FRAM_default_system_init_state = 0xAA;
			IAP_FRAM_WRITE(STORAGE_PARM_DEFAULT_SYSTEM_BASE + FRAM_SYSTEM_FLAG_ADDR, &FRAM_default_system_init_state, 1);
		}

		if (FRAM_defalut_app_init_state != 0xAA) {
			uint8_t data[APP_REGION_SIZE - 4];
			IAP_FRAM_READ(STORAGE_PARM_APP_BASE, data, APP_REGION_SIZE - 4);
			IAP_FRAM_WRITE(STORAGE_PARM_DEFAULT_APP_BASE, data, APP_REGION_SIZE - 4);
			
			FRAM_defalut_app_init_state = 0xAA;
			IAP_FRAM_WRITE(STORAGE_PARM_DEFAULT_APP_BASE + FRAM_APP_FLAG_ADDR, &FRAM_defalut_app_init_state, 1);
		}
	} else {
		FRAM_store_mode = FRAM_NORMAL_MODE;
	}
}

/*****************************************************************************
 * @brief 获取当前是默认还是动态区接口函数
 * ex:
 * @par
 * None
 * @retval
 *****************************************************************************/
uint8_t PPGetStoreMode(void)
{
	return FRAM_store_mode;
}

#endif


/******************* (C) COPYRIGHT 2021 CIQTEK Moon *****END OF FILE****/
